package com.warrior.superdata.util;

/**
 * Created by chenzy on 2017/7/15.
 */

import com.alibaba.druid.util.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * @author H__D
 * @date 2016年10月19日 上午11:27:25
 *
 */
public class HttpClientUtil {

	// utf-8字符编码
	public static final String CHARSET_UTF_8 = "utf-8";

	// HTTP内容类型。
	public static final String CONTENT_TYPE_TEXT_HTML = "text/xml";

	// HTTP内容类型。相当于form表单的形式，提交数据
	public static final String CONTENT_TYPE_FORM_URL = "application/x-www-form-urlencoded";

	// HTTP内容类型。相当于form表单的形式，提交数据
	public static final String CONTENT_TYPE_JSON_URL = "application/json;charset=utf-8";

	// 连接管理器
	private static PoolingHttpClientConnectionManager pool;

	// 请求配置
	private static RequestConfig requestConfig;

	// 因为请求groupService的接口返回状态码大于300的时候没有返回信息,所以在这里定义一个失败的常量;
	private static String Fail_Request = "{'request':'fail'}";

	protected final static Logger log = LoggerFactory
			.getLogger(HttpClientUtil.class);

	static {

		try {
			SSLContextBuilder builder = new SSLContextBuilder();
			builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
			SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
					builder.build());
			// 配置同时支持 HTTP 和 HTPPS
			Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
					.<ConnectionSocketFactory> create()
					.register("http",
							PlainConnectionSocketFactory.getSocketFactory())
					.register("https", sslsf).build();
			// 初始化连接管理器
			pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
			// 将最大连接数增加到200，实际项目最好从配置文件中读取这个值
			pool.setMaxTotal(200);
			// 设置最大路由
			pool.setDefaultMaxPerRoute(2);
			// 根据默认超时限制初始化requestConfig
			int socketTimeout = 300000;
			int connectTimeout = 300000;
			int connectionRequestTimeout = 300000;
			requestConfig = RequestConfig.custom()
					.setConnectionRequestTimeout(connectionRequestTimeout)
					.setSocketTimeout(socketTimeout)
					.setConnectTimeout(connectTimeout).build();

		} catch (NoSuchAlgorithmException e) {
			log.error("The exception is:", e);
		} catch (KeyStoreException e) {
			log.error("The exception is:", e);
		} catch (KeyManagementException e) {
			log.error("The exception is:", e);
		}

		// 设置请求超时时间
		requestConfig = RequestConfig.custom().setSocketTimeout(300000)
				.setConnectTimeout(300000).setConnectionRequestTimeout(300000)
				.build();
	}

	public static CloseableHttpClient getHttpClient() {

		CloseableHttpClient httpClient = HttpClients.custom()
				// 设置连接池管理
				.setConnectionManager(pool)
				// 设置请求配置
				.setDefaultRequestConfig(requestConfig)
				// 设置重试次数
				.setRetryHandler(new DefaultHttpRequestRetryHandler(0, false))
				.build();

		return httpClient;
	}

	/**
	 * 发送Post请求
	 *
	 * @param httpPost
	 * @return
	 */
	private static String sendHttpPost(HttpPost httpPost) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		// 响应内容
		String responseContent = null;
		// 判断响应状态
		try {
			// 创建默认的httpClient实例.
			httpClient = getHttpClient();
			// 配置请求信息
			httpPost.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpPost);
			// 得到响应实例
			HttpEntity entity = response.getEntity();

			// 可以获得响应头
			// Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE);
			// for (Header header : headers) {
			// }

			// 得到响应类型
			responseContent = EntityUtils.toString(entity, CHARSET_UTF_8);
			// 判断响应状态
			if (response.getStatusLine().getStatusCode() >= 300) {
				log.error("======= httpclent返回的状态码大于等于300 =======");
				if (StringUtils.isEmpty(responseContent)){
					return Fail_Request;
				}
			}
			if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
				EntityUtils.consume(entity);
			}

		} catch (Exception e) {
			log.error("The exception is:", e);
		} finally {
			try {
				// 释放资源
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				log.error("The exception is:", e);
			}
		}
		return responseContent;
	}

	/**
	 * 发送put请求
	 * @param httpPut
	 * @return
	 */
	private static String sendHttpPut(HttpPut httpPut) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		// 响应内容
		String responseContent = null;
		try {
			// 创建默认的httpClient实例.
			httpClient = getHttpClient();
			// 配置请求信息
			httpPut.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpPut);
			// 得到响应实例
			HttpEntity entity = response.getEntity();

			// 可以获得响应头
			// Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE);
			// for (Header header : headers) {
			// }

			responseContent = EntityUtils.toString(entity, CHARSET_UTF_8);
			// 判断响应状态
			if (response.getStatusLine().getStatusCode() >= 300) {
				log.error("====== httpclent返回的状态码大于等于300 ======");
				if (StringUtils.isEmpty(responseContent)) {
					return Fail_Request;
				}
			}

			if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
				EntityUtils.consume(entity);
			}

		} catch (Exception e) {
			log.error("The exception is:", e);
		} finally {
			try {
				// 释放资源
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				log.error("The exception is:", e);
			}
		}
		return responseContent;
	}

	/**
	 * 发送Get请求
	 *
	 * @param httpGet
	 * @return
	 */
	private static String sendHttpGet(HttpGet httpGet) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		// 响应内容
		String responseContent = null;
		try {
			// 创建默认的httpClient实例.
			httpClient = getHttpClient();
			// 配置请求信息
			httpGet.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpGet);
			// 得到响应实例
			HttpEntity entity = response.getEntity();

			// 可以获得响应头
			// Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE);
			// for (Header header : headers) {
			// }

			responseContent = EntityUtils.toString(entity, CHARSET_UTF_8);
			// 判断响应状态
			if (response.getStatusLine().getStatusCode() >= 300) {
				throw new Exception(
						"HTTP Request is not success, Response code is "
								+ response.getStatusLine().getStatusCode());
			}

			if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
				EntityUtils.consume(entity);
			}

		} catch (Exception e) {
			log.error("The exception is:", e);
		} finally {
			try {
				// 释放资源
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				log.error("The exception is:", e);
			}
		}
		return responseContent;
	}


	/**
	 * 发送Delete请求
	 *
	 * @param httpDelete
	 * @return
	 */
	private static String sendHttpDelete(HttpDelete httpDelete) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		// 响应内容
		String responseContent = null;
		try {
			// 创建默认的httpClient实例.
			httpClient = getHttpClient();
			// 配置请求信息
			httpDelete.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpDelete);
			// 得到响应实例
			HttpEntity entity = response.getEntity();

			// 可以获得响应头
			// Header[] headers = response.getHeaders(HttpHeaders.CONTENT_TYPE);
			// for (Header header : headers) {
			// }

			responseContent = EntityUtils.toString(entity, CHARSET_UTF_8);
			// 判断响应状态
			
			 if (response.getStatusLine().getStatusCode() >= 300) {
				 log.error("======= httpclent返回的状态码大于等于300 =======");
				 if (StringUtils.isEmpty(responseContent)) {
					 return Fail_Request;
				 }
			 }
			if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
				EntityUtils.consume(entity);
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		} finally {
			try {
				// 释放资源
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				log.error("The exception is:", e);
			}
		}
		return responseContent;
	}

	/**
	 * 发送 post请求
	 *
	 * @param httpUrl
	 *            地址
	 */
	public static String sendHttpPost(String httpUrl) {
		// 创建httpPost
		HttpPost httpPost = new HttpPost(httpUrl);
		return sendHttpPost(httpPost);
	}

	/**
	 * 发送 get请求
	 *
	 * @param httpUrl
	 */
	public static String sendHttpGet(String httpUrl, Map<String, String> headers) {
		// 创建get请求
		HttpGet httpGet = new HttpGet(httpUrl);
		if (headers != null) {
			Set<String> keys = headers.keySet();
			for (Iterator<String> i = keys.iterator(); i.hasNext();) {
				String key = (String) i.next();
				httpGet.addHeader(key, headers.get(key));
			}
		}
		return sendHttpGet(httpGet);
	}

	/**
	 * 发送delete请求
	 *
	 * @param httpUrl
	 */
	public static String sendHttpDelete(String httpUrl, Map<String, String> headers) {
		// 创建get请求
		HttpDelete httpDelete = new HttpDelete(httpUrl);
		if (headers != null) {
			Set<String> keys = headers.keySet();
			for (Iterator<String> i = keys.iterator(); i.hasNext();) {
				String key = (String) i.next();
				httpDelete.addHeader(key, headers.get(key));
			}
		}
		return sendHttpDelete(httpDelete);
	}

	/**
	 * 发送 get请求
	 *
	 * @param httpUrl
	 */
	public static InputStream sendHttpGetStream(String httpUrl,
			Map<String, String> headers) {
		// 创建get请求
		HttpGet httpGet = new HttpGet(httpUrl);
		if (headers != null) {
			Set<String> keys = headers.keySet();
			for (Iterator<String> i = keys.iterator(); i.hasNext();) {
				String key = (String) i.next();
				httpGet.addHeader(key, headers.get(key));
			}
		}
		return sendHttpGetStream(httpGet);
	}

	/**
	 * 发送Get请求
	 *
	 * @param httpGet
	 * @return
	 */
	private static InputStream sendHttpGetStream(HttpGet httpGet) {

		CloseableHttpClient httpClient = null;
		CloseableHttpResponse response = null;
		// 响应内容
		HttpEntity entity = null;
		// 储存的流对象
		InputStream inputStream = null;
		try {
			// 创建默认的httpClient实例.
			httpClient = getHttpClient();
			// 配置请求信息
			httpGet.setConfig(requestConfig);
			// 执行请求
			response = httpClient.execute(httpGet);
			// 得到响应实例
			entity = response.getEntity();
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			InputStream input = entity.getContent();
			byte[] buffer = new byte[1024];
			int len;
			while ((len = input.read(buffer)) != -1) {
				baos.write(buffer, 0, len);
			}
			input.close();
			baos.flush();
			inputStream = new ByteArrayInputStream(baos.toByteArray());
			// 判断响应状态
			if (response.getStatusLine().getStatusCode() >= 300) {
				throw new Exception(
						"HTTP Request is not success, Response code is "
								+ response.getStatusLine().getStatusCode());
			}
			if (HttpStatus.SC_OK == response.getStatusLine().getStatusCode()) {
				EntityUtils.consume(entity);
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		} finally {
			try {
				// 释放资源
				if (response != null) {
					response.close();
				}
			} catch (IOException e) {
				log.error("The exception is:", e);
			}
		}
		try {
			return inputStream;
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return null;
	}

	/**
	 * 发送 post请求
	 *
	 * @param httpUrl
	 *            地址
	 * @param params
	 *            参数(格式:key1=value1&key2=value2)
	 * @param headers
	 *            http header 请求头
	 *
	 */
	public static String sendHttpPost(String httpUrl, String params,
			Map<String, String> headers) {
		HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
		try {
			// 设置参数
			if (params != null && params.trim().length() > 0) {
				StringEntity stringEntity = new StringEntity(params, "UTF-8");
				stringEntity.setContentType(CONTENT_TYPE_FORM_URL);
				httpPost.setEntity(stringEntity);
			}
			if (headers != null) {
				Set<String> keys = headers.keySet();
				for (Iterator<String> i = keys.iterator(); i.hasNext();) {
					String key = (String) i.next();
					httpPost.addHeader(key, headers.get(key));
				}
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 发送 post请求
	 *
	 * @param maps
	 *            参数
	 * @param headers
	 *            http 请求头
	 */
	public static String sendHttpPost(String httpUrl, Map<String, String> maps,
			Map<String, String> headers) {
		String parem = convertStringParamter(maps);
		return sendHttpPost(httpUrl, parem, headers);
	}

	/**
	 * 发送 post请求 发送json数据
	 *
	 * @param httpUrl
	 *            地址
	 * @param paramsJson
	 *            参数(格式 json)
	 * @param headers
	 *            http 请求头
	 */
	public static String sendHttpPostJson(String httpUrl, String paramsJson,
			Map<String, String> headers) {
		HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
		try {
			// 设置参数
			if (paramsJson != null && paramsJson.trim().length() > 0) {
				StringEntity stringEntity = new StringEntity(paramsJson,
						"UTF-8");
				stringEntity.setContentType(CONTENT_TYPE_JSON_URL);
				httpPost.setEntity(stringEntity);
			}
			if (headers != null) {
				Set<String> keys = headers.keySet();
				for (Iterator<String> i = keys.iterator(); i.hasNext();) {
					String key = (String) i.next();
					httpPost.addHeader(key, headers.get(key));
				}
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 发送 put请求 发送json数据
	 *
	 * @param httpUrl
	 *            地址
	 * @param paramsJson
	 *            参数(格式 json)
	 * @param headers
	 *            http 请求头
	 */
	public static String sendHttpPutJson(String httpUrl, String paramsJson,
			Map<String, String> headers) {
		HttpPut httpPut = new HttpPut(httpUrl);// 创建httpPost
		try {
			// 设置参数
			if (paramsJson != null && paramsJson.trim().length() > 0) {
				StringEntity stringEntity = new StringEntity(paramsJson,
						"UTF-8");
				stringEntity.setContentType(CONTENT_TYPE_JSON_URL);
				httpPut.setEntity(stringEntity);
			}
			if (headers != null) {
				Set<String> keys = headers.keySet();
				for (Iterator<String> i = keys.iterator(); i.hasNext();) {
					String key = (String) i.next();
					httpPut.addHeader(key, headers.get(key));
				}
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return sendHttpPut(httpPut);
	}

	/**
	 * 发送 delete请求 发送json数据
	 *
	 * @param httpUrl
	 *            地址
	 * @param paramsJson
	 *            参数(格式 json)
	 * @param headers
	 *            http 请求头
	 */
	public static String sendHttpDeleteJson(String httpUrl, Map paramsJson,
			Map<String, String> headers) {
		if (paramsJson != null) {
			httpUrl = httpUrl + "?" + convertStringParamter(paramsJson);
		}
		HttpDelete httpDelete = new HttpDelete(httpUrl);// 创建httpPost
		try {
			// 设置参数
			/*
			 * if (paramsJson != null && paramsJson.trim().length() > 0) {
			 * StringEntity stringEntity = new StringEntity(paramsJson,
			 * "UTF-8"); stringEntity.setContentType(CONTENT_TYPE_JSON_URL);
			 * ((HttpResponse) httpDelete).setEntity(stringEntity); }
			 */
			if (headers != null) {
				Set<String> keys = headers.keySet();
				for (Iterator<String> i = keys.iterator(); i.hasNext();) {
					String key = (String) i.next();
					httpDelete.addHeader(key, headers.get(key));
				}
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return sendHttpDelete(httpDelete);
	}


	/**
	 * 发送 post请求 发送xml数据
	 *
	 * @param httpUrl
	 *            地址
	 * @param paramsXml
	 *            参数(格式 Xml)
	 * @param headers
	 *            http 请求头
	 */
	public static String sendHttpPostXml(String httpUrl, String paramsXml,
			Map<String, String> headers) {
		HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
		try {
			// 设置参数
			if (paramsXml != null && paramsXml.trim().length() > 0) {
				StringEntity stringEntity = new StringEntity(paramsXml, "UTF-8");
				stringEntity.setContentType(CONTENT_TYPE_TEXT_HTML);
				httpPost.setEntity(stringEntity);
			}
			if (headers != null) {
				Set<String> keys = headers.keySet();
				for (Iterator<String> i = keys.iterator(); i.hasNext();) {
					String key = (String) i.next();
					httpPost.addHeader(key, headers.get(key));
				}
			}
		} catch (Exception e) {
			log.error("The exception is:", e);
		}
		return sendHttpPost(httpPost);
	}

	/**
	 * 将map集合的键值对转化成：key1=value1&key2=value2 的形式
	 *
	 * @param parameterMap
	 *            需要转化的键值对集合
	 * @return 字符串
	 */
	public static String convertStringParamter(Map parameterMap) {
		StringBuffer parameterBuffer = new StringBuffer();
		if (parameterMap != null) {
			Iterator iterator = parameterMap.keySet().iterator();
			String key = null;
			String value = null;
			List<String> list = new ArrayList<String>();
			while (iterator.hasNext()) {
				key = (String) iterator.next();
				if (!key.contains("List") && parameterMap.get(key) != null) {
					value = (String) parameterMap.get(key) == null ? ""
							: (String) parameterMap.get(key);
				} else {
					list = (List<String>) parameterMap.get(key);
					/*
					 * if(list != null && list.size()>0){ for (String string :
					 * list) { value = value + string + ","; } value =
					 * value.substring(0, value.length()-1); }else{ value = "";
					 * }
					 */
					if (list != null && list.size() > 0) {
						for (String string : list) {
							parameterBuffer.append(key).append("=")
									.append(string);
							if (iterator.hasNext()) {
								parameterBuffer.append("&");
							}
						}
					} else {
						value = "";
					}
					continue;
				}
				parameterBuffer.append(key).append("=").append(value);
				if (iterator.hasNext()) {
					parameterBuffer.append("&");
				}
			}
		}
		return parameterBuffer.toString();
	}

}